package com.learnosity.extendotext
{
	import flash.text.engine.ElementFormat;
	import com.learnosity.extendotext.style.*;
	import flash.utils.Dictionary;
		
	public class StyleSheet
	{
		protected var _content:String;
		protected var rules:Vector.<RuleSet>;
		private var ruleMapper:Dictionary;
		
		
		public function StyleSheet()
		{
			ruleMapper = new Dictionary();
			ruleMapper['color'] = Color;
			ruleMapper['font-family'] = FontFamily;
			ruleMapper['font-size'] = FontSize;
			ruleMapper['font-style'] = FontStyle;
			ruleMapper['font-weight'] = FontWeight;
			ruleMapper['opacity'] = Opacity;
			ruleMapper['vertical-align'] = VerticalAlign;
		}
		
		/**
		 * Set the styles
		 */
		public function set content(value:String):void{
			this._content = value;
			parseContent();
		}
		public function get content():String{
			return this._content
		}
		
		/**
		 * Find the rule that matches a particular selector
		 * Note: Only single direct matches are currently supported
		 */
		public function findRules(element:String):Vector.<RuleSet>
		{
			var matchedRules:Vector.<RuleSet> = new Vector.<RuleSet>();
			
			//Loop through current rules and match any rules with same selectors
			//TODO: Need to add rules for complex selector here
			for each (var ruleset:RuleSet in this.rules){
				if(ruleset.selector == element){
					matchedRules.push(ruleset);
				}
			}
			return matchedRules;
		}

		/**
		 * gets a Text Engine formatting object based on a number of stylesheet rules
		 */
		public function getFormattingObject(rules:Vector.<RuleSet>,format:ElementFormat=null):ElementFormat{
			//var format:ElementFormat = new ElementFormat();
			if(format == null){
			 format = new ElementFormat();
			}
			 else{
			 	format = format.clone();
			 }
			
			//Loop through each of the matched rules
			for each (var ruleset:RuleSet in rules){
				trace('selector: '+ruleset.selector);
				//Apply each item from rule in order
				for each( var rule:Rule in ruleset.rules){
					trace('rule: '+rule.name );
				
					if(ruleMapper[rule.name] != null){
						//Pass the rule and current formatting off to current object
						format = ruleMapper[rule.name].apply(rule,format);				
					}else{
						trace('Unhandled rule: '+rule.name);
					}
				}
			}
			
			
			return format;
		}


		
		
		
		
//  -------------------------------------------------
//	Private & Protected functions below here
//  -------------------------------------------------


		protected function parseContent():void{			
			trace('Parsing content');
			//Strip all comments
			var commentRegexp:RegExp = /\/\*(?:.|[\r\n])*?\*\//g; 
			var cleanContent:String = this._content.replace(commentRegexp,'');
			trace(cleanContent);
			var thisRule:RuleSet;

			//Clean out any old rules
			this.rules = new Vector.<RuleSet>();

			//TODO: handle @ statements
			//TODO: handle blocks
			
			//Parse out each rule set
			//split on each closing }
			var contentArray:Array = cleanContent.split('}');
			//loop through and split selector and ruleset
			for(var i:int=0; i < contentArray.length; i++){
				thisRule = new RuleSet();
				var tmp:Array = String(contentArray[i]).split('{');			
				tmp[0] = trim(tmp[0]);
				if(tmp[0].length){	
					rules.push(thisRule);
					thisRule.selector = tmp[0];
					trace ("Selector: "+thisRule.selector);
					for(var j:int=1; j < tmp.length; j++)
					{ 
						var tmpRuleArr:Array = String(tmp[j]).split(';');
						for(var k:int=0; k < tmpRuleArr.length; k++){
							if(trim(tmpRuleArr[k]).length){
							
								var tmpValues:Array = String(tmpRuleArr[k]).split(':');					
								if(trim(tmpValues[0]).length){
									//trace(String(tmpValues[0]).length);
									var tmpRule:Rule = new Rule();
									tmpRule.name = trim(tmpValues[0]);
									tmpRule.value = trim(tmpValues[1]);
									trace('Rule: '+tmpRule.name + '::'+tmpRule.value);
									thisRule.rules.push(tmpRule);
								}
							}
						}
					}
				}
			}
			
			trace('Parsed rules: '+rules.length);
			
			//Loop through each section
			//Loop through each item 
		}



    /**
     *  Removes all whitespace characters from the beginning and end
     *  of the specified string.
     *
     *  @param str The String whose whitespace should be trimmed. 
     *
     *  @return Updated String where whitespace was removed from the 
     *  beginning and end. 
     */
    public static function trim(str:String):String
    {
        if (str == null) return '';
        
        var startIndex:int = 0;
        while (isWhitespace(str.charAt(startIndex)))
            ++startIndex;

        var endIndex:int = str.length - 1;
        while (isWhitespace(str.charAt(endIndex)))
            --endIndex;

        if (endIndex >= startIndex)
            return str.slice(startIndex, endIndex + 1);
        else
            return "";
    }
    
    /**
     *  Returns <code>true</code> if the specified string is
     *  a single space, tab, carriage return, newline, or formfeed character.
     *
     *  @param str The String that is is being queried. 
     *
     *  @return <code>true</code> if the specified string is
     *  a single space, tab, carriage return, newline, or formfeed character.
     */
    public static function isWhitespace(character:String):Boolean
    {
        switch (character)
        {
            case " ":
            case "\t":
            case "\r":
            case "\n":
            case "\f":
                return true;

            default:
                return false;
        }
    }

	}
}